// util funcs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



// transform timestamp into standard
// todo: handle timezones by first bringing into Date etc
Date.prototype.format = function() {
	return this.getFullYear()
		+'-'+( (this.getMonth()+1<10 )	? '0'+(this.getMonth()+1)	: this.getMonth()	)
		+'-'+( (this.getDate()<10 )	? '0'+this.getDate()		: this.getDate()		)
		+' '+( (this.getHours()<10 )	? '0'+this.getHours()		: this.getHours()	)
		+':'+( (this.getMinutes()<10 )	? '0'+this.getMinutes()		: this.getMinutes()	);
}

// get radio value from form (or document)
HTMLFormElement.prototype.getRadio= function( itemName ) {
	var btns = this.elements[itemName];
	if( btns == undefined ) return null;
	// one element - must be checked
	if( btns.value != undefined ) return (btns.checked) ? btns.value : null;
	// many elements
	for( var i=0; i<btns.length; i++ )  if( btns[i].checked ) break;
	// if fall thru null, otherwise value
	return (i<btns.length) ? btns[i].value : null;
}
function cs__getRadio( form, itemName ) {
	// if form is string, convert to element
	if( typeof form == 'string' ) form = document.getElementById(form);
	var btns = (form) ? form.elements[itemName] : document.getElementsByName(itemName);
	if( btns == undefined ) return null;
	// one element - must be checked
	if( btns.value != undefined ) return (btns.checked) ? btns.value : null;
	// many elements
	for( var i=0; i<btns.length; i++ ) {
		var btn = btns[i];
		if( btn.checked ) return btn.value;
	}
	return null;
}
// get radio value from form (or document)
HTMLFormElement.prototype.setRadio = function( itemName, value ) {
	var btns = this.elements[itemName];
	if( btns == undefined ) return;
	// one element - check if == value
	if( btns.value == value ) {
		btns.checked = true;
		return;
	}
	// many elements - check if == value
	for( var i=0; i<btns.length; i++ )  if( btns[i].value == value ){
		btns[i].checked = true;
		return;
	}
	// if fall thru null, otherwise value
	return;
}
// set radio value from form (or document)
function cs__setRadio( form, itemName, value ) {
	// if form is string, convert to element
	if( typeof form == 'string' ) form = document.getElementById(form);
	var btns = (form) ? form.elements[itemName] : document.getElementsByName(itemName);
	if( btns == undefined ) return null;
	// one element - must be checked
	if( btns.value != undefined ) btns.checked = ( btns.value == value );
	// many elements
	for( var i=0; i<btns.length; i++ ) {
		var btn = btns[i];
		btn.checked = (btn.value == value );
	}
}

// todo: purify string
String.prototype.purify = function() {
	return this.toString();
}

// nonblocking Alert
function nonblockAlert( msg ) {
	if( typeof msg != 'string' ) msg = msg.toString();
	msg = msg.replace(/"/g,'\\"');
	msg = msg.replace(/\n/g,"\\n");
	setTimeout( 'window.alert("'+msg+'")', 0 );
}
//
// add option to select
HTMLSelectElement.prototype.appendOption = function( value, label, select_value ) {
	var opt = document.createElement('option');
	opt.value = value;
	opt.appendChild( document.createTextNode( (label==undefined)?value:label ) );
	opt.checked = ( select_value != undefined && select_value == value );
	this.appendChild( opt );
}
// whether self or parent has attribute or attribute == val
Element.prototype.ancestorByAttribute = function( attr, val, myself ) {
	for( var node=(myself)?this:this.parentNode; true; node=node.parentNode ) {
		if( node.getAttribute(attr) != undefined &&( val == undefined || node.getAttribute(attr) == val )) return node;
		if( node.tagName == 'BODY' ) return null;
	}
	return undefined;
}
// get first element of node with tagName
Element.prototype.ancestorByTagName = function( tagName ) {
	for( var node=this.parentNode; true; node=node.parentNode ) {
		if( node.tagName == tagName ) return node;
		if( node.tagName == 'BODY' ) return null;
	}
	return undefined;
}
// get first element of node with className
// todo: use regx instead of classList for chrome
Element.prototype.ancestorByClassName = function( className, myself ) {
	for( var node=(myself)?this:this.parentNode; true; node=node.parentNode ) {
		if( node.classList.contains(className) ) return node;
		if( node.tagName == 'BODY' ) return null;
	}
	return undefined;
}

// merge elements of arg into this
Element.prototype.merge = function( mergee ) {

	// cannot be self
	if( this == mergee ) throw( 'cannot merge with self' );

	// null mergee - nada
	if( !mergee ) return self;

	// pull elements from the front of merge into this
	// note: do not need to remove node from mergee - it is moved with the appendChild
	for( var i=0; mergee.firstChild && i<100; i++ ) this.appendChild(mergee.firstChild);

	// safety check
	if( i>=100 ) throw( 'did not pull all from mergee' );

	// remove mergee
	mergee.parentNode.removeChild( mergee );

	return self;
}

// toggle style.display for this element
// todo: no longer needed under css3!
// arg display: true = <block>, false = 'none', undefined = <toggle>
Element.prototype.displayToggle = function( display ) {
	if( display == undefined ) display = ( this.style.display == 'none' );
	if( !display )				this.style.display = 'none';
	else if( this.tagName == 'DIV' )	this.style.display = 'block';
	else if( this.tagName == 'FORM' )	this.style.display = 'block';
	else if( this.tagName == 'TABLE' )	this.style.display = 'table';
	else if( this.tagName == 'TR' )		this.style.display = 'table-row';
	else if( this.tagName == 'TD' )		this.style.display = 'table-cell';
	else if( this.tagName == 'TH' )		this.style.display = 'table-cell';
	else					throw( 'displayToggle - not handling '+this.tagName );
}

// get move associated with this element
Element.prototype.cs__getMove = function() {
	if( this.getAttribute('move_id') == undefined ) return null;
	else return chess_spider.state.moves[this.getAttribute('move_id')];
}
// get movelist container parent
Element.prototype.cs__getMoveList = function() {

	// move up until we find movelist_continer
	for( var i=0, dom = this; dom.className != 'cs__movelist_container'; i++, dom=dom.parentNode ) {
		if( !dom.parentNode ) throw( 'null parent node' );
		if( i>10 ) throw( 'movelist parent too high' );
	}

	// return movelist
	return chess_spider.params.movelists[dom.id];
}

// get fixedboard container parent
Element.prototype.cs__getFixedBoard = function() {

	// move up until we find fixedboard_continer
	for( var dom = this; true; dom=dom.parentNode ) {
		if( dom.tagName == 'BODY' ) return null;
		if( dom.className == 'cs__fixedboard_container' ) break;
	}

	// return fixedboard
	return chess_spider.params.fixedboards[dom.id];
}

// get board from board table or board container
Element.prototype.cs__getBoard = function() {

	// move up until we find board_continer
	for( var dom = this; true; dom=dom.parentNode ) {
		if( dom.tagName == 'BODY' ) return null;
		if( dom.className == 'cs__board_container' ) break;
	}

	// if fixedboard, outer container
	var fixedboard = dom.cs__getFixedBoard();
	if( fixedboard ) return fixedboard.board;

	// dynamic, get from href
	else if( dom.parentNode.className == 'cs__comment' ) {

		// find href preceding - will be last (perhaps only) href in the move span preceding the comment
		var href = dom.parentNode.previousSibling.lastChild;
		if( href.tagName != 'A' ) href = href.previousSibling;

		// make sure we're there
		if( href.tagName != 'A' ) throw( 'illegal dom to getBoardFromHTML - no href' );

		// use href.move_id attribute
		return chess_spider.state.moves[href.getAttribute('move_id')].board;
	}

	else	throw( 'illegal dom to getBoardFromHTML - neither cs__fixedboard_container nor cs__comment' );
}

// util functions
chess_spider.util.getFile = function( square ) {
	return square[0];
}
chess_spider.util.incFile = function( square ) {
	return String.fromCharCode(square.charCodeAt(0)+1);
}
chess_spider.util.inc2File = function( square ) {
	return chess_spider.util.incFile(chess_spider.util.incFile(square));
}
chess_spider.util.decFile = function( square ) {
	return String.fromCharCode(square.charCodeAt(0)-1);
}
chess_spider.util.dec2File = function( square ) {
	return chess_spider.util.decFile(chess_spider.util.decFile(square));
}
chess_spider.util.ordFile = function( square ) {
	return square.charCodeAt(0) - "a".charCodeAt(0) + 1;
}
chess_spider.util.getRank = function( square ) {
	return (typeof(square)=='number') ? square : parseInt(square[1]);
}
chess_spider.util.incRank = function( square ) {
	return (typeof(square)=='number') ? square+1 : parseInt(square[1])+1;
}
chess_spider.util.inc2Rank = function( square ) {
	return (typeof(square)=='number') ? square+2 : parseInt(square[1])+2;
}
chess_spider.util.decRank = function( square ) {
	return (typeof(square)=='number') ? square-1 : parseInt(square[1])-1;
}
chess_spider.util.dec2Rank = function( square ) {
	return (typeof(square)=='number') ? square-2 : parseInt(square[1])-2;
}

// sequence - for generating unique id's
chess_spider.util.seq = 0;
chess_spider.util.nextSeq = function() {
	chess_spider.util.seq++;
	return chess_spider.util.seq;
}

// extract last name (ignore suffixes)
String.prototype.lastName = function() {
	var match_arr = this.match( /^ *([^,]*), *(.*)/ );
	if( !match_arr || !match_arr[0] ) return this;
	else return match_arr[1] + ', ' + match_arr[2][0];
}
String.prototype.firstName = function() {
	var match_arr = this.match( /^ *([^,]*), *(.*)/ );
	if( !match_arr || !match_arr[0] ) return this;
	else return match_arr[2] + ' ' + match_arr[1];
}

// Array.has == in_array
Array.prototype.has = function( element ) {
	for( var i=0; i<this.length; i++ ) if( this[i] == element ) return true;
	return false;
}

// array indexOf
Array.prototype.indexOf = function( element ) {
	for( var i=0; i<this.length; i++ ) if( this[i] == element ) return i;
	return null;
}

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function( from, to ) {
	var rest = this.slice((to || from) + 1 || this.length);
	this.length = from < 0 ? this.length + from : from;
	return this.push.apply(this, rest);
};

// Array.unique - destructive, returns self
Array.prototype.unique = function() {
	var arr = new Array;
	for( var i=0; i<this.length; i++ ) {
		if( !arr.has(this[i]) ) arr.push( this[i] );
	}
	return arr;
}

// null event
function nullEvent(e) {
	if( !e ) e = window.event;
	e.stopPropagation();
	e.preventDefault();
}

